home *** CD-ROM | disk | FTP | other *** search
/ Team Palmtops 7 / Palmtops_numero07.iso / WinCE / SDKWindowsCE / HandHeldPCPro30 / sdk.exe / Jupiter SDK / data1.cab / MFC / src / viewscrl.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  1999-02-19  |  29.1 KB  |  1,130 lines

  1. // This is a part of the Microsoft Foundation Classes C++ library.
  2. // Copyright (C) 1992-1998 Microsoft Corporation
  3. // All rights reserved.
  4. //
  5. // This source code is only intended as a supplement to the
  6. // Microsoft Foundation Classes Reference and related
  7. // electronic documentation provided with the library.
  8. // See these sources for detailed information regarding the
  9. // Microsoft Foundation Classes product.
  10.  
  11. #include "stdafx.h"
  12.  
  13. #ifdef AFX_CORE2_SEG
  14. #pragma code_seg(AFX_CORE2_SEG)
  15. #endif
  16.  
  17. #ifdef _DEBUG
  18. #undef THIS_FILE
  19. static char THIS_FILE[] = __FILE__;
  20. #endif
  21.  
  22. /////////////////////////////////////////////////////////////////////////////
  23. // CScrollView
  24.  
  25. BEGIN_MESSAGE_MAP(CScrollView, CView)
  26.     //{{AFX_MSG_MAP(CScrollView)
  27.     ON_WM_SIZE()
  28.     ON_WM_HSCROLL()
  29.     ON_WM_VSCROLL()
  30. WCE_DEL ON_WM_MOUSEWHEEL()
  31.     //}}AFX_MSG_MAP
  32. END_MESSAGE_MAP()
  33.  
  34. // Special mapping modes just for CScrollView implementation
  35. #define MM_NONE             0
  36. #define MM_SCALETOFIT       (-1)
  37.     // standard GDI mapping modes are > 0
  38.  
  39. #if !defined(_WIN32_WCE)
  40. extern BOOL _afxGotScrollLines;    // defined in wincore.cpp
  41.  
  42. UINT PASCAL _AfxGetMouseScrollLines()
  43. {
  44.     static UINT uCachedScrollLines;
  45.  
  46.     // if we've already got it and we're not refreshing,
  47.     // return what we've already got
  48.  
  49.     if (_afxGotScrollLines)
  50.         return uCachedScrollLines;
  51.  
  52.     // see if we can find the mouse window
  53.  
  54.     _afxGotScrollLines = TRUE;
  55.  
  56.     static UINT msgGetScrollLines;
  57.     static WORD nRegisteredMessage;
  58.  
  59.     if (nRegisteredMessage == 0)
  60.     {
  61.         msgGetScrollLines = ::RegisterWindowMessage(MSH_SCROLL_LINES);
  62.         if (msgGetScrollLines == 0)
  63.             nRegisteredMessage = 1;     // couldn't register!  never try again
  64.         else
  65.             nRegisteredMessage = 2;     // it worked: use it
  66.     }
  67.  
  68.     if (nRegisteredMessage == 2)
  69.     {
  70.         HWND hwMouseWheel = NULL;
  71.         hwMouseWheel = FindWindow(MSH_WHEELMODULE_CLASS, MSH_WHEELMODULE_TITLE);
  72.         if (hwMouseWheel && msgGetScrollLines)
  73.         {
  74.             uCachedScrollLines = (UINT)
  75.                 ::SendMessage(hwMouseWheel, msgGetScrollLines, 0, 0);
  76.             return uCachedScrollLines;
  77.         }
  78.     }
  79.  
  80.     // couldn't use the window -- try system settings
  81.     uCachedScrollLines = 3; // reasonable default
  82.     if (!afxData.bWin4)
  83.     {
  84.         HKEY hKey;
  85.         if (RegOpenKeyEx(HKEY_CURRENT_USER,  _T("Control Panel\\Desktop"),
  86.                 0, KEY_QUERY_VALUE, &hKey) == ERROR_SUCCESS)
  87.         {
  88.             TCHAR szData[128];
  89.             DWORD dwKeyDataType;
  90.             DWORD dwDataBufSize = _countof(szData);
  91.  
  92.             if (RegQueryValueEx(hKey, _T("WheelScrollLines"), NULL, &dwKeyDataType,
  93.                     (LPBYTE) &szData, &dwDataBufSize) == ERROR_SUCCESS)
  94.             {
  95.                 uCachedScrollLines = _tcstoul(szData, NULL, 10);
  96.             }
  97.             RegCloseKey(hKey);
  98.         }
  99.     }
  100.     else if (!afxData.bWin95)
  101.     {
  102.         ::SystemParametersInfo(SPI_GETWHEELSCROLLLINES, 0, &uCachedScrollLines, 0);
  103.     }
  104.  
  105.     return uCachedScrollLines;
  106. }
  107. #endif // _WIN32_WCE
  108.  
  109. /////////////////////////////////////////////////////////////////////////////
  110. // CScrollView construction/destruction
  111.  
  112. CScrollView::CScrollView()
  113. {
  114.     // Init everything to zero
  115.     AFX_ZERO_INIT_OBJECT(CView);
  116.  
  117.     m_nMapMode = WCE_IF(MM_TEXT,MM_NONE);
  118. }
  119.  
  120. CScrollView::~CScrollView()
  121. {
  122. }
  123.  
  124. /////////////////////////////////////////////////////////////////////////////
  125. // CScrollView painting
  126.  
  127. #if defined(_WIN32_WCE_NO_PRINTING)
  128. void CScrollView::OnPrepareDC(CDC* pDC, const void* pUnused)
  129. #else // _WIN32_WCE_NO_PRINTING
  130. void CScrollView::OnPrepareDC(CDC* pDC, CPrintInfo* pInfo)
  131. #endif // _WIN32_WCE_NO_PRINTING
  132. {
  133.     ASSERT_VALID(pDC);
  134.  
  135. #ifdef _DEBUG
  136.     if (m_nMapMode == MM_NONE)
  137.     {
  138.         TRACE0("Error: must call SetScrollSizes() or SetScaleToFitSize()");
  139.         TRACE0("\tbefore painting scroll view.\n");
  140.         ASSERT(FALSE);
  141.         return;
  142.     }
  143. #endif //_DEBUG
  144.     ASSERT(m_totalDev.cx >= 0 && m_totalDev.cy >= 0);
  145.     switch (m_nMapMode)
  146.     {
  147.     case MM_SCALETOFIT:
  148. #if !defined(_WIN32_WCE_NO_GDITRANSFORM)
  149.         pDC->SetMapMode(MM_ANISOTROPIC);
  150.         pDC->SetWindowExt(m_totalLog);  // window is in logical coordinates
  151.         pDC->SetViewportExt(m_totalDev);
  152. #endif // _WIN32_WCE_NO_GDITRANSFORM
  153.         if (m_totalDev.cx == 0 || m_totalDev.cy == 0)
  154.             TRACE0("Warning: CScrollView scaled to nothing.\n");
  155.         break;
  156.  
  157.     default:
  158. #if defined(_WIN32_WCE_NO_GDITRANSFORM)
  159.         ASSERT(m_nMapMode == MM_TEXT);
  160. #else // _WIN32_WCE_NO_GDITRANSFORM
  161.         ASSERT(m_nMapMode > 0);
  162.         pDC->SetMapMode(m_nMapMode);
  163. #endif // _WIN32_WCE_NO_GDITRANSFORM
  164.         break;
  165.     }
  166.  
  167. #if !defined(_WIN32_WCE_NO_PRINTING)
  168.     CPoint ptVpOrg(0, 0);       // assume no shift for printing
  169.     if (!pDC->IsPrinting())
  170.     {
  171.         ASSERT(pDC->GetWindowOrg() == CPoint(0,0));
  172.  
  173.         // by default shift viewport origin in negative direction of scroll
  174.         ptVpOrg = -GetDeviceScrollPosition();
  175.  
  176.         if (m_bCenter)
  177.         {
  178.             CRect rect;
  179.             GetClientRect(&rect);
  180.  
  181.             // if client area is larger than total device size,
  182.             // override scroll positions to place origin such that
  183.             // output is centered in the window
  184.             if (m_totalDev.cx < rect.Width())
  185.                 ptVpOrg.x = (rect.Width() - m_totalDev.cx) / 2;
  186.             if (m_totalDev.cy < rect.Height())
  187.                 ptVpOrg.y = (rect.Height() - m_totalDev.cy) / 2;
  188.         }
  189.     }
  190. #if !defined(_WIN32_WCE_NO_GDITRANSFORM)
  191.     pDC->SetViewportOrg(ptVpOrg);
  192. #endif // _WIN32_WCE_NO_GDITRANSFORM
  193. #endif // _WIN32_WCE_NO_PRINTING
  194.  
  195. #if defined(_WIN32_WCE_NO_PRINTING)
  196.     CView::OnPrepareDC(pDC, pUnused);
  197. #else // _WIN32_WCE_NO_PRINTING
  198.     CView::OnPrepareDC(pDC, pInfo);     // For default Printing behavior
  199. #endif // _WIN32_WCE_NO_PRINTING
  200. }
  201.  
  202. /////////////////////////////////////////////////////////////////////////////
  203. // Set mode and scaling/scrolling sizes
  204.  
  205. void CScrollView::SetScaleToFitSize(SIZE sizeTotal)
  206. {
  207. #if !defined(_WIN32_WCE_NO_GDITRANSFORM)
  208.     // Note: It is possible to set sizeTotal members to negative values to
  209.     //  effectively invert either the X or Y axis.
  210.  
  211.     ASSERT(m_hWnd != NULL);
  212.     m_nMapMode = MM_SCALETOFIT;     // special internal value
  213.     m_totalLog = sizeTotal;
  214.  
  215.     // reset and turn any scroll bars off
  216.     if (m_hWnd != NULL && (GetStyle() & (WS_HSCROLL|WS_VSCROLL)))
  217.     {
  218.         SetScrollPos(SB_HORZ, 0);
  219.         SetScrollPos(SB_VERT, 0);
  220.         EnableScrollBarCtrl(SB_BOTH, FALSE);
  221.         ASSERT((GetStyle() & (WS_HSCROLL|WS_VSCROLL)) == 0);
  222.     }
  223.  
  224.     CRect rectT;
  225.     GetClientRect(rectT);
  226.     m_totalDev = rectT.Size();
  227.  
  228.     if (m_hWnd != NULL)
  229.     {
  230.         // window has been created, invalidate
  231.         UpdateBars();
  232.         Invalidate(TRUE);
  233.     }
  234. #endif // _WIN32_WCE_NO_GDITRANSFORM
  235. }
  236.  
  237. const AFX_DATADEF SIZE CScrollView::sizeDefault = {0,0};
  238.  
  239. void CScrollView::SetScrollSizes(int nMapMode, SIZE sizeTotal,
  240.     const SIZE& sizePage, const SIZE& sizeLine)
  241. {
  242.     ASSERT(sizeTotal.cx >= 0 && sizeTotal.cy >= 0);
  243. #if defined(_WIN32_WCE_NO_GDITRANSFORM)
  244.     ASSERT(nMapMode == MM_TEXT);
  245. #else // _WIN32_WCE_NO_GDITRANSFORM
  246.     ASSERT(nMapMode > 0);
  247.     ASSERT(nMapMode != MM_ISOTROPIC && nMapMode != MM_ANISOTROPIC);
  248. #endif // _WIN32_WCE_NO_GDITRANSFORM
  249.  
  250.     int nOldMapMode = m_nMapMode;
  251.     m_nMapMode = nMapMode;
  252.     m_totalLog = sizeTotal;
  253.  
  254.     //BLOCK: convert logical coordinate space to device coordinates
  255.     {
  256.         CWindowDC dc(NULL);
  257.         ASSERT(m_nMapMode > 0);
  258. #if !defined(_WIN32_WCE_NO_GDITRANSFORM)
  259.         dc.SetMapMode(m_nMapMode);
  260. #endif // _WIN32_WCE_NO_GDITRANSFORM
  261.  
  262.         // total size
  263.         m_totalDev = m_totalLog;
  264.         dc.LPtoDP((LPPOINT)&m_totalDev);
  265.         m_pageDev = sizePage;
  266.         dc.LPtoDP((LPPOINT)&m_pageDev);
  267.         m_lineDev = sizeLine;
  268.         dc.LPtoDP((LPPOINT)&m_lineDev);
  269.         if (m_totalDev.cy < 0)
  270.             m_totalDev.cy = -m_totalDev.cy;
  271.         if (m_pageDev.cy < 0)
  272.             m_pageDev.cy = -m_pageDev.cy;
  273.         if (m_lineDev.cy < 0)
  274.             m_lineDev.cy = -m_lineDev.cy;
  275.     } // release DC here
  276.  
  277.     // now adjust device specific sizes
  278.     ASSERT(m_totalDev.cx >= 0 && m_totalDev.cy >= 0);
  279.     if (m_pageDev.cx == 0)
  280.         m_pageDev.cx = m_totalDev.cx / 10;
  281.     if (m_pageDev.cy == 0)
  282.         m_pageDev.cy = m_totalDev.cy / 10;
  283.     if (m_lineDev.cx == 0)
  284.         m_lineDev.cx = m_pageDev.cx / 10;
  285.     if (m_lineDev.cy == 0)
  286.         m_lineDev.cy = m_pageDev.cy / 10;
  287.  
  288.     if (m_hWnd != NULL)
  289.     {
  290.         // window has been created, invalidate now
  291.         UpdateBars();
  292.         if (nOldMapMode != m_nMapMode)
  293.             Invalidate(TRUE);
  294.     }
  295. }
  296.  
  297. /////////////////////////////////////////////////////////////////////////////
  298. // Getting information
  299.  
  300. CPoint CScrollView::GetScrollPosition() const   // logical coordinates
  301. {
  302.     if (m_nMapMode == MM_SCALETOFIT)
  303.     {
  304.         return CPoint(0, 0);    // must be 0,0
  305.     }
  306.  
  307.     CPoint pt = GetDeviceScrollPosition();
  308.     // pt may be negative if m_bCenter is set
  309.  
  310. #if defined(_WIN32_WCE_NO_GDITRANSFORM)
  311.     ASSERT(m_nMapMode == MM_TEXT);
  312. #else // _WIN32_WCE_NO_GDITRANSFORM
  313.     if (m_nMapMode != MM_TEXT)
  314.     {
  315.         ASSERT(m_nMapMode > 0); // must be set
  316.         CWindowDC dc(NULL);
  317.         dc.SetMapMode(m_nMapMode);
  318.         dc.DPtoLP((LPPOINT)&pt);
  319.     }
  320. #endif // _WIN32_WCE_NO_GDITRANSFORM
  321.     return pt;
  322. }
  323.  
  324. void CScrollView::ScrollToPosition(POINT pt)    // logical coordinates
  325. {
  326. #if defined(_WIN32_WCE_NO_GDITRANSFORM)
  327.     ASSERT(m_nMapMode == MM_TEXT);
  328. #else // _WIN32_WCE_NO_GDITRANSFORM
  329.     ASSERT(m_nMapMode > 0);     // not allowed for shrink to fit
  330.     if (m_nMapMode != MM_TEXT)
  331.     {
  332.         CWindowDC dc(NULL);
  333.         dc.SetMapMode(m_nMapMode);
  334.         dc.LPtoDP((LPPOINT)&pt);
  335.     }
  336. #endif // _WIN32_WCE_NO_GDITRANSFORM
  337.  
  338.     // now in device coordinates - limit if out of range
  339.     int xMax = GetScrollLimit(SB_HORZ);
  340.     int yMax = GetScrollLimit(SB_VERT);
  341.     if (pt.x < 0)
  342.         pt.x = 0;
  343.     else if (pt.x > xMax)
  344.         pt.x = xMax;
  345.     if (pt.y < 0)
  346.         pt.y = 0;
  347.     else if (pt.y > yMax)
  348.         pt.y = yMax;
  349.  
  350.     ScrollToDevicePosition(pt);
  351. }
  352.  
  353. CPoint CScrollView::GetDeviceScrollPosition() const
  354. {
  355.     CPoint pt(GetScrollPos(SB_HORZ), GetScrollPos(SB_VERT));
  356.     ASSERT(pt.x >= 0 && pt.y >= 0);
  357.  
  358.     if (m_bCenter)
  359.     {
  360.         CRect rect;
  361.         GetClientRect(&rect);
  362.  
  363.         // if client area is larger than total device size,
  364.         // the scroll positions are overridden to place origin such that
  365.         // output is centered in the window
  366.         // GetDeviceScrollPosition() must reflect this
  367.  
  368.         if (m_totalDev.cx < rect.Width())
  369.             pt.x = -((rect.Width() - m_totalDev.cx) / 2);
  370.         if (m_totalDev.cy < rect.Height())
  371.             pt.y = -((rect.Height() - m_totalDev.cy) / 2);
  372.     }
  373.  
  374.     return pt;
  375. }
  376.  
  377. void CScrollView::GetDeviceScrollSizes(int& nMapMode, SIZE& sizeTotal,
  378.             SIZE& sizePage, SIZE& sizeLine) const
  379. {
  380.     if (m_nMapMode <= 0)
  381.         TRACE0("Warning: CScrollView::GetDeviceScrollSizes returning invalid mapping mode.\n");
  382.     nMapMode = m_nMapMode;
  383.     sizeTotal = m_totalDev;
  384.     sizePage = m_pageDev;
  385.     sizeLine = m_lineDev;
  386. }
  387.  
  388. void CScrollView::ScrollToDevicePosition(POINT ptDev)
  389. {
  390.     ASSERT(ptDev.x >= 0);
  391.     ASSERT(ptDev.y >= 0);
  392.  
  393.     // Note: ScrollToDevicePosition can and is used to scroll out-of-range
  394.     //  areas as far as CScrollView is concerned -- specifically in
  395.     //  the print-preview code.  Since OnScrollBy makes sure the range is
  396.     //  valid, ScrollToDevicePosition does not vector through OnScrollBy.
  397.  
  398.     int xOrig = GetScrollPos(SB_HORZ);
  399.     SetScrollPos(SB_HORZ, ptDev.x);
  400.     int yOrig = GetScrollPos(SB_VERT);
  401.     SetScrollPos(SB_VERT, ptDev.y);
  402.     ScrollWindow(xOrig - ptDev.x, yOrig - ptDev.y);
  403. }
  404.  
  405. /////////////////////////////////////////////////////////////////////////////
  406. // Other helpers
  407.  
  408. void CScrollView::FillOutsideRect(CDC* pDC, CBrush* pBrush)
  409. {
  410.     ASSERT_VALID(pDC);
  411.     ASSERT_VALID(pBrush);
  412.  
  413.     // fill rect outside the image
  414.     CRect rect;
  415.     GetClientRect(rect);
  416.     ASSERT(rect.left == 0 && rect.top == 0);
  417.     rect.left = m_totalDev.cx;
  418.     if (!rect.IsRectEmpty())
  419.         pDC->FillRect(rect, pBrush);    // vertical strip along the side
  420.     rect.left = 0;
  421.     rect.right = m_totalDev.cx;
  422.     rect.top = m_totalDev.cy;
  423.     if (!rect.IsRectEmpty())
  424.         pDC->FillRect(rect, pBrush);    // horizontal strip along the bottom
  425. }
  426.  
  427. void CScrollView::ResizeParentToFit(BOOL bShrinkOnly)
  428. {
  429.     // adjust parent rect so client rect is appropriate size
  430.     ASSERT(m_nMapMode != MM_NONE);  // mapping mode must be known
  431.  
  432.     // determine current size of the client area as if no scrollbars present
  433.     CRect rectClient;
  434.     GetWindowRect(rectClient);
  435.     CRect rect = rectClient;
  436.     CalcWindowRect(rect);
  437.     rectClient.left += rectClient.left - rect.left;
  438.     rectClient.top += rectClient.top - rect.top;
  439.     rectClient.right -= rect.right - rectClient.right;
  440.     rectClient.bottom -= rect.bottom - rectClient.bottom;
  441.     rectClient.OffsetRect(-rectClient.left, -rectClient.top);
  442.     ASSERT(rectClient.left == 0 && rectClient.top == 0);
  443.  
  444.     // determine desired size of the view
  445.     CRect rectView(0, 0, m_totalDev.cx, m_totalDev.cy);
  446.     if (bShrinkOnly)
  447.     {
  448.         if (rectClient.right <= m_totalDev.cx)
  449.             rectView.right = rectClient.right;
  450.         if (rectClient.bottom <= m_totalDev.cy)
  451.             rectView.bottom = rectClient.bottom;
  452.     }
  453.     CalcWindowRect(rectView, CWnd::adjustOutside);
  454.     rectView.OffsetRect(-rectView.left, -rectView.top);
  455.     ASSERT(rectView.left == 0 && rectView.top == 0);
  456.     if (bShrinkOnly)
  457.     {
  458.         if (rectClient.right <= m_totalDev.cx)
  459.             rectView.right = rectClient.right;
  460.         if (rectClient.bottom <= m_totalDev.cy)
  461.             rectView.bottom = rectClient.bottom;
  462.     }
  463.  
  464.     // dermine and set size of frame based on desired size of view
  465.     CRect rectFrame;
  466.     CFrameWnd* pFrame = GetParentFrame();
  467.     ASSERT_VALID(pFrame);
  468.     pFrame->GetWindowRect(rectFrame);
  469.     CSize size = rectFrame.Size();
  470.     size.cx += rectView.right - rectClient.right;
  471.     size.cy += rectView.bottom - rectClient.bottom;
  472.     pFrame->SetWindowPos(NULL, 0, 0, size.cx, size.cy,
  473.         SWP_NOMOVE|SWP_NOZORDER|SWP_NOACTIVATE);
  474. }
  475.  
  476. /////////////////////////////////////////////////////////////////////////////
  477.  
  478. void CScrollView::OnSize(UINT nType, int cx, int cy)
  479. {
  480.     CView::OnSize(nType, cx, cy);
  481.     if (m_nMapMode == MM_SCALETOFIT)
  482.     {
  483.         // force recalculation of scale to fit parameters
  484.         SetScaleToFitSize(m_totalLog);
  485.     }
  486.     else
  487.     {
  488.         // UpdateBars() handles locking out recursion
  489.         UpdateBars();
  490.     }
  491. }
  492.  
  493. /////////////////////////////////////////////////////////////////////////////
  494. // Scrolling Helpers
  495.  
  496. void CScrollView::CenterOnPoint(CPoint ptCenter) // center in device coords
  497. {
  498.     CRect rect;
  499.     GetClientRect(&rect);           // find size of client window
  500.  
  501.     int xDesired = ptCenter.x - rect.Width() / 2;
  502.     int yDesired = ptCenter.y - rect.Height() / 2;
  503.  
  504.     DWORD dwStyle = GetStyle();
  505.  
  506.     if ((dwStyle & WS_HSCROLL) == 0 || xDesired < 0)
  507.     {
  508.         xDesired = 0;
  509.     }
  510.     else
  511.     {
  512.         int xMax = GetScrollLimit(SB_HORZ);
  513.         if (xDesired > xMax)
  514.             xDesired = xMax;
  515.     }
  516.  
  517.     if ((dwStyle & WS_VSCROLL) == 0 || yDesired < 0)
  518.     {
  519.         yDesired = 0;
  520.     }
  521.     else
  522.     {
  523.         int yMax = GetScrollLimit(SB_VERT);
  524.         if (yDesired > yMax)
  525.             yDesired = yMax;
  526.     }
  527.  
  528.     ASSERT(xDesired >= 0);
  529.     ASSERT(yDesired >= 0);
  530.  
  531.     SetScrollPos(SB_HORZ, xDesired);
  532.     SetScrollPos(SB_VERT, yDesired);
  533. }
  534.  
  535. /////////////////////////////////////////////////////////////////////////////
  536. // Tie to scrollbars and CWnd behaviour
  537.  
  538. void CScrollView::GetScrollBarSizes(CSize& sizeSb)
  539. {
  540.     sizeSb.cx = sizeSb.cy = 0;
  541.     DWORD dwStyle = GetStyle();
  542.  
  543.     if (GetScrollBarCtrl(SB_VERT) == NULL)
  544.     {
  545.         // vert scrollbars will impact client area of this window
  546.         sizeSb.cx = afxData.cxVScroll;
  547.         if (dwStyle & WS_BORDER)
  548.             sizeSb.cx -= CX_BORDER;
  549.     }
  550.     if (GetScrollBarCtrl(SB_HORZ) == NULL)
  551.     {
  552.         // horz scrollbars will impact client area of this window
  553.         sizeSb.cy = afxData.cyHScroll;
  554.         if (dwStyle & WS_BORDER)
  555.             sizeSb.cy -= CY_BORDER;
  556.     }
  557. }
  558.  
  559. BOOL CScrollView::GetTrueClientSize(CSize& size, CSize& sizeSb)
  560.     // return TRUE if enough room to add scrollbars if needed
  561. {
  562.     CRect rect;
  563.     GetClientRect(&rect);
  564.     ASSERT(rect.top == 0 && rect.left == 0);
  565.     size.cx = rect.right;
  566.     size.cy = rect.bottom;
  567.     DWORD dwStyle = GetStyle();
  568.  
  569.     // first get the size of the scrollbars for this window
  570.     GetScrollBarSizes(sizeSb);
  571.  
  572.     // first calculate the size of a potential scrollbar
  573.     // (scroll bar controls do not get turned on/off)
  574.     if (sizeSb.cx != 0 && (dwStyle & WS_VSCROLL))
  575.     {
  576.         // vert scrollbars will impact client area of this window
  577.         size.cx += sizeSb.cx;   // currently on - adjust now
  578.     }
  579.     if (sizeSb.cy != 0 && (dwStyle & WS_HSCROLL))
  580.     {
  581.         // horz scrollbars will impact client area of this window
  582.         size.cy += sizeSb.cy;   // currently on - adjust now
  583.     }
  584.  
  585.     // return TRUE if enough room
  586.     return (size.cx > sizeSb.cx && size.cy > sizeSb.cy);
  587. }
  588.  
  589. // helper to return the state of the scrollbars without actually changing
  590. //  the state of the scrollbars
  591. void CScrollView::GetScrollBarState(CSize sizeClient, CSize& needSb,
  592.     CSize& sizeRange, CPoint& ptMove, BOOL bInsideClient)
  593. {
  594.     // get scroll bar sizes (the part that is in the client area)
  595.     CSize sizeSb;
  596.     GetScrollBarSizes(sizeSb);
  597.  
  598.     // enough room to add scrollbars
  599.     sizeRange = m_totalDev - sizeClient;
  600.         // > 0 => need to scroll
  601.     ptMove = GetDeviceScrollPosition();
  602.         // point to move to (start at current scroll pos)
  603.  
  604.     BOOL bNeedH = sizeRange.cx > 0;
  605.     if (!bNeedH)
  606.         ptMove.x = 0;                       // jump back to origin
  607.     else if (bInsideClient)
  608.         sizeRange.cy += sizeSb.cy;          // need room for a scroll bar
  609.  
  610.     BOOL bNeedV = sizeRange.cy > 0;
  611.     if (!bNeedV)
  612.         ptMove.y = 0;                       // jump back to origin
  613.     else if (bInsideClient)
  614.         sizeRange.cx += sizeSb.cx;          // need room for a scroll bar
  615.  
  616.     if (bNeedV && !bNeedH && sizeRange.cx > 0)
  617.     {
  618.         ASSERT(bInsideClient);
  619.         // need a horizontal scrollbar after all
  620.         bNeedH = TRUE;
  621.         sizeRange.cy += sizeSb.cy;
  622.     }
  623.  
  624.     // if current scroll position will be past the limit, scroll to limit
  625.     if (sizeRange.cx > 0 && ptMove.x >= sizeRange.cx)
  626.         ptMove.x = sizeRange.cx;
  627.     if (sizeRange.cy > 0 && ptMove.y >= sizeRange.cy)
  628.         ptMove.y = sizeRange.cy;
  629.  
  630.     // now update the bars as appropriate
  631.     needSb.cx = bNeedH;
  632.     needSb.cy = bNeedV;
  633.  
  634.     // needSb, sizeRange, and ptMove area now all updated
  635. }
  636.  
  637. void CScrollView::UpdateBars()
  638. {
  639.     // UpdateBars may cause window to be resized - ignore those resizings
  640.     if (m_bInsideUpdate)
  641.         return;         // Do not allow recursive calls
  642.  
  643.     // Lock out recursion
  644.     m_bInsideUpdate = TRUE;
  645.  
  646.     // update the horizontal to reflect reality
  647.     // NOTE: turning on/off the scrollbars will cause 'OnSize' callbacks
  648.     ASSERT(m_totalDev.cx >= 0 && m_totalDev.cy >= 0);
  649.  
  650.     CRect rectClient;
  651.     BOOL bCalcClient = TRUE;
  652.  
  653.     // allow parent to do inside-out layout first
  654.     CWnd* pParentWnd = GetParent();
  655.     if (pParentWnd != NULL)
  656.     {
  657.         // if parent window responds to this message, use just
  658.         //  client area for scroll bar calc -- not "true" client area
  659.         if ((BOOL)pParentWnd->SendMessage(WM_RECALCPARENT, 0,
  660.             (LPARAM)(LPCRECT)&rectClient) != 0)
  661.         {
  662.             // use rectClient instead of GetTrueClientSize for
  663.             //  client size calculation.
  664.             bCalcClient = FALSE;
  665.         }
  666.     }
  667.  
  668.     CSize sizeClient;
  669.     CSize sizeSb;
  670.  
  671.     if (bCalcClient)
  672.     {
  673.         // get client rect
  674.         if (!GetTrueClientSize(sizeClient, sizeSb))
  675.         {
  676.             // no room for scroll bars (common for zero sized elements)
  677.             CRect rect;
  678.             GetClientRect(&rect);
  679.             if (rect.right > 0 && rect.bottom > 0)
  680.             {
  681.                 // if entire client area is not invisible, assume we have
  682.                 //  control over our scrollbars
  683.                 EnableScrollBarCtrl(SB_BOTH, FALSE);
  684.             }
  685.             m_bInsideUpdate = FALSE;
  686.             return;
  687.         }
  688.     }
  689.     else
  690.     {
  691.         // let parent window determine the "client" rect
  692.         GetScrollBarSizes(sizeSb);
  693.         sizeClient.cx = rectClient.right - rectClient.left;
  694.         sizeClient.cy = rectClient.bottom - rectClient.top;
  695.     }
  696.  
  697.     // enough room to add scrollbars
  698.     CSize sizeRange;
  699.     CPoint ptMove;
  700.     CSize needSb;
  701.  
  702.     // get the current scroll bar state given the true client area
  703.     GetScrollBarState(sizeClient, needSb, sizeRange, ptMove, bCalcClient);
  704.     if (needSb.cx)
  705.         sizeClient.cy -= sizeSb.cy;
  706.     if (needSb.cy)
  707.         sizeClient.cx -= sizeSb.cx;
  708.  
  709.     // first scroll the window as needed
  710.     ScrollToDevicePosition(ptMove); // will set the scroll bar positions too
  711.  
  712.     // this structure needed to update the scrollbar page range
  713.     SCROLLINFO info;
  714. #if defined(_WIN32_WCE)
  715.     memset( &info, 0, sizeof(SCROLLINFO) );
  716.     info.cbSize = sizeof(SCROLLINFO);
  717. #endif // _WIN32_WCE
  718.     info.fMask = SIF_PAGE|SIF_RANGE;
  719.     info.nMin = 0;
  720.  
  721.     // now update the bars as appropriate
  722.     EnableScrollBarCtrl(SB_HORZ, needSb.cx);
  723.     if (needSb.cx)
  724.     {
  725.         info.nPage = sizeClient.cx;
  726.         info.nMax = m_totalDev.cx-1;
  727.         if (!SetScrollInfo(SB_HORZ, &info, TRUE))
  728.             SetScrollRange(SB_HORZ, 0, sizeRange.cx, TRUE);
  729.     }
  730.     EnableScrollBarCtrl(SB_VERT, needSb.cy);
  731.     if (needSb.cy)
  732.     {
  733.         info.nPage = sizeClient.cy;
  734.         info.nMax = m_totalDev.cy-1;
  735.         if (!SetScrollInfo(SB_VERT, &info, TRUE))
  736.             SetScrollRange(SB_VERT, 0, sizeRange.cy, TRUE);
  737.     }
  738.  
  739.     // remove recursion lockout
  740.     m_bInsideUpdate = FALSE;
  741. }
  742.  
  743. void CScrollView::CalcWindowRect(LPRECT lpClientRect, UINT nAdjustType)
  744. {
  745.     if (nAdjustType == adjustOutside)
  746.     {
  747.         // allow for special client-edge style
  748.         ::AdjustWindowRectEx(lpClientRect, 0, FALSE, GetExStyle());
  749.  
  750.         if (m_nMapMode != MM_SCALETOFIT)
  751.         {
  752.             // if the view is being used in-place, add scrollbar sizes
  753.             //  (scollbars should appear on the outside when in-place editing)
  754.             CSize sizeClient(
  755.                 lpClientRect->right - lpClientRect->left,
  756.                 lpClientRect->bottom - lpClientRect->top);
  757.  
  758.             CSize sizeRange = m_totalDev - sizeClient;
  759.                 // > 0 => need to scroll
  760.  
  761.             // get scroll bar sizes (used to adjust the window)
  762.             CSize sizeSb;
  763.             GetScrollBarSizes(sizeSb);
  764.  
  765.             // adjust the window size based on the state
  766.             if (sizeRange.cy > 0)
  767.             {   // vertical scroll bars take up horizontal space
  768.                 lpClientRect->right += sizeSb.cx;
  769.             }
  770.             if (sizeRange.cx > 0)
  771.             {   // horizontal scroll bars take up vertical space
  772.                 lpClientRect->bottom += sizeSb.cy;
  773.             }
  774.         }
  775.     }
  776.     else
  777.     {
  778.         // call default to handle other non-client areas
  779.         ::AdjustWindowRectEx(lpClientRect, WCE_IF(GetStyle() & ~(WS_HSCROLL | WS_VSCROLL), GetStyle()), FALSE,
  780.             GetExStyle() & ~(WS_EX_CLIENTEDGE));
  781.     }
  782. }
  783.  
  784. /////////////////////////////////////////////////////////////////////////////
  785. // CScrollView scrolling
  786.  
  787. void CScrollView::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
  788. {
  789.     if (pScrollBar != NULL && pScrollBar->SendChildNotifyLastMsg())
  790.         return;     // eat it
  791.  
  792. #if defined(_WIN32_WCE)  
  793. // WinCE:  If GetScrollBarCtrl is NULL, don't ignore message
  794.     CScrollBar* pTemp;
  795.     if(pTemp = GetScrollBarCtrl(SB_VERT))
  796.     {
  797.         if(pScrollBar != pTemp) 
  798.             return;
  799.     }
  800. #else // _WIN32_WCE
  801.     // ignore scroll bar msgs from other controls
  802.     if (pScrollBar != GetScrollBarCtrl(SB_HORZ))
  803.         return;
  804. #endif // _WIN32_WCE
  805.  
  806.     OnScroll(MAKEWORD(nSBCode, -1), nPos);
  807. }
  808.  
  809. void CScrollView::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
  810. {
  811.     if (pScrollBar != NULL && pScrollBar->SendChildNotifyLastMsg())
  812.         return;     // eat it
  813.  
  814. #if defined(_WIN32_WCE)  
  815. // WinCE:  If GetScrollBarCtrl is NULL, don't ignore message
  816.     CScrollBar* pTemp;
  817.     if(pTemp = GetScrollBarCtrl(SB_VERT))
  818.     {
  819.         if(pScrollBar != pTemp) 
  820.             return;
  821.     }
  822. #else // _WIN32_WCE
  823.     // ignore scroll bar msgs from other controls
  824.     if (pScrollBar != GetScrollBarCtrl(SB_VERT))
  825.         return;
  826. #endif // _WIN32_WCE
  827.  
  828.     OnScroll(MAKEWORD(-1, nSBCode), nPos);
  829. }
  830.  
  831. #if !defined(_WIN32_WCE)
  832. BOOL CScrollView::OnMouseWheel(UINT fFlags, short zDelta, CPoint point)
  833. {
  834.     // we don't handle anything but scrolling just now
  835.     if (fFlags & (MK_SHIFT | MK_CONTROL))
  836.         return FALSE;
  837.  
  838.     // if the parent is a splitter, it will handle the message
  839.     if (GetParentSplitter(this, TRUE))
  840.         return FALSE;
  841.  
  842.     // we can't get out of it--perform the scroll ourselves
  843.     return DoMouseWheel(fFlags, zDelta, point);
  844. }
  845.  
  846. // This function isn't virtual. If you need to override it,
  847. // you really need to override OnMouseWheel() here or in
  848. // CSplitterWnd.
  849.  
  850. BOOL CScrollView::DoMouseWheel(UINT fFlags, short zDelta, CPoint point)
  851. {
  852.     UNUSED_ALWAYS(point);
  853.     UNUSED_ALWAYS(fFlags);
  854.  
  855.     // if we have a vertical scroll bar, the wheel scrolls that
  856.     // if we have _only_ a horizontal scroll bar, the wheel scrolls that
  857.     // otherwise, don't do any work at all
  858.  
  859.     DWORD dwStyle = GetStyle();
  860.     CScrollBar* pBar = GetScrollBarCtrl(SB_VERT);
  861.     BOOL bHasVertBar = ((pBar != NULL) && pBar->IsWindowEnabled()) ||
  862.                     (dwStyle & WS_VSCROLL);
  863.  
  864.     pBar = GetScrollBarCtrl(SB_HORZ);
  865.     BOOL bHasHorzBar = ((pBar != NULL) && pBar->IsWindowEnabled()) ||
  866.                     (dwStyle & WS_HSCROLL);
  867.  
  868.     if (!bHasVertBar && !bHasHorzBar)
  869.         return FALSE;
  870.  
  871.     BOOL bResult = FALSE;
  872.     UINT uWheelScrollLines = _AfxGetMouseScrollLines();
  873.     int nToScroll;
  874.     int nDisplacement;
  875.  
  876.     if (bHasVertBar)
  877.     {
  878.         nToScroll = ::MulDiv(-zDelta, uWheelScrollLines, WHEEL_DELTA);
  879.         if (nToScroll == -1 || uWheelScrollLines == WHEEL_PAGESCROLL)
  880.         {
  881.             nDisplacement = m_pageDev.cy;
  882.             if (zDelta > 0)
  883.                 nDisplacement = -nDisplacement;
  884.         }
  885.         else
  886.         {
  887.             nDisplacement = nToScroll * m_lineDev.cy;
  888.             nDisplacement = min(nDisplacement, m_pageDev.cy);
  889.         }
  890.         bResult = OnScrollBy(CSize(0, nDisplacement), TRUE);
  891.     }
  892.     else if (bHasHorzBar)
  893.     {
  894.         nToScroll = ::MulDiv(-zDelta, uWheelScrollLines, WHEEL_DELTA);
  895.         if (nToScroll == -1 || uWheelScrollLines == WHEEL_PAGESCROLL)
  896.         {
  897.             nDisplacement = m_pageDev.cx;
  898.             if (zDelta > 0)
  899.                 nDisplacement = -nDisplacement;
  900.         }
  901.         else
  902.         {
  903.             nDisplacement = nToScroll * m_lineDev.cx;
  904.             nDisplacement = min(nDisplacement, m_pageDev.cx);
  905.         }
  906.         bResult = OnScrollBy(CSize(nDisplacement, 0), TRUE);
  907.     }
  908.  
  909.     if (bResult)
  910.         UpdateWindow();
  911.  
  912.     return bResult;
  913. }
  914.  
  915. #endif // _WIN32_WCE
  916.  
  917. BOOL CScrollView::OnScroll(UINT nScrollCode, UINT nPos, BOOL bDoScroll)
  918. {
  919.     // calc new x position
  920.     int x = GetScrollPos(SB_HORZ);
  921.     int xOrig = x;
  922.  
  923.     switch (LOBYTE(nScrollCode))
  924.     {
  925.     case SB_TOP:
  926.         x = 0;
  927.         break;
  928.     case SB_BOTTOM:
  929.         x = INT_MAX;
  930.         break;
  931.     case SB_LINEUP:
  932.         x -= m_lineDev.cx;
  933.         break;
  934.     case SB_LINEDOWN:
  935.         x += m_lineDev.cx;
  936.         break;
  937.     case SB_PAGEUP:
  938.         x -= m_pageDev.cx;
  939.         break;
  940.     case SB_PAGEDOWN:
  941.         x += m_pageDev.cx;
  942.         break;
  943.     case SB_THUMBTRACK:
  944.         x = nPos;
  945.         break;
  946.     }
  947.  
  948.     // calc new y position
  949.     int y = GetScrollPos(SB_VERT);
  950.     int yOrig = y;
  951.  
  952.     switch (HIBYTE(nScrollCode))
  953.     {
  954.     case SB_TOP:
  955.         y = 0;
  956.         break;
  957.     case SB_BOTTOM:
  958.         y = INT_MAX;
  959.         break;
  960.     case SB_LINEUP:
  961.         y -= m_lineDev.cy;
  962.         break;
  963.     case SB_LINEDOWN:
  964.         y += m_lineDev.cy;
  965.         break;
  966.     case SB_PAGEUP:
  967.         y -= m_pageDev.cy;
  968.         break;
  969.     case SB_PAGEDOWN:
  970.         y += m_pageDev.cy;
  971.         break;
  972.     case SB_THUMBTRACK:
  973.         y = nPos;
  974.         break;
  975.     }
  976.  
  977.     BOOL bResult = OnScrollBy(CSize(x - xOrig, y - yOrig), bDoScroll);
  978.     if (bResult && bDoScroll)
  979.         UpdateWindow();
  980.  
  981.     return bResult;
  982. }
  983.  
  984. BOOL CScrollView::OnScrollBy(CSize sizeScroll, BOOL bDoScroll)
  985. {
  986.     int xOrig, x;
  987.     int yOrig, y;
  988.  
  989.     // don't scroll if there is no valid scroll range (ie. no scroll bar)
  990.     CScrollBar* pBar;
  991.     DWORD dwStyle = GetStyle();
  992.     pBar = GetScrollBarCtrl(SB_VERT);
  993.     if ((pBar != NULL && !pBar->IsWindowEnabled()) ||
  994.         (pBar == NULL && !(dwStyle & WS_VSCROLL)))
  995.     {
  996.         // vertical scroll bar not enabled
  997.         sizeScroll.cy = 0;
  998.     }
  999.     pBar = GetScrollBarCtrl(SB_HORZ);
  1000.     if ((pBar != NULL && !pBar->IsWindowEnabled()) ||
  1001.         (pBar == NULL && !(dwStyle & WS_HSCROLL)))
  1002.     {
  1003.         // horizontal scroll bar not enabled
  1004.         sizeScroll.cx = 0;
  1005.     }
  1006.  
  1007.     // adjust current x position
  1008.     xOrig = x = GetScrollPos(SB_HORZ);
  1009.     int xMax = GetScrollLimit(SB_HORZ);
  1010.     x += sizeScroll.cx;
  1011.     if (x < 0)
  1012.         x = 0;
  1013.     else if (x > xMax)
  1014.         x = xMax;
  1015.  
  1016.     // adjust current y position
  1017.     yOrig = y = GetScrollPos(SB_VERT);
  1018.     int yMax = GetScrollLimit(SB_VERT);
  1019.     y += sizeScroll.cy;
  1020.     if (y < 0)
  1021.         y = 0;
  1022.     else if (y > yMax)
  1023.         y = yMax;
  1024.  
  1025.     // did anything change?
  1026.     if (x == xOrig && y == yOrig)
  1027.         return FALSE;
  1028.  
  1029.     if (bDoScroll)
  1030.     {
  1031.         // do scroll and update scroll positions
  1032. #if defined(_WIN32_WCE)   
  1033.         wce_ScrollChildren(m_hWnd, (x-xOrig), (y-yOrig));
  1034. #endif // _WIN32_WCE
  1035.         ScrollWindow(-(x-xOrig), -(y-yOrig));
  1036.         if (x != xOrig)
  1037.             SetScrollPos(SB_HORZ, x);
  1038.         if (y != yOrig)
  1039.             SetScrollPos(SB_VERT, y);
  1040.     }
  1041.     return TRUE;
  1042. }
  1043.  
  1044. /////////////////////////////////////////////////////////////////////////////
  1045. // CScrollView diagnostics
  1046.  
  1047. #ifdef _DEBUG
  1048. void CScrollView::Dump(CDumpContext& dc) const
  1049. {
  1050.     CView::Dump(dc);
  1051.  
  1052.     dc << "m_totalLog = " << m_totalLog;
  1053.     dc << "\nm_totalDev = " << m_totalDev;
  1054.     dc << "\nm_pageDev = " << m_pageDev;
  1055.     dc << "\nm_lineDev = " << m_lineDev;
  1056.     dc << "\nm_bCenter = " << m_bCenter;
  1057.     dc << "\nm_bInsideUpdate = " << m_bInsideUpdate;
  1058.     dc << "\nm_nMapMode = ";
  1059.     switch (m_nMapMode)
  1060.     {
  1061.     case MM_NONE:
  1062.         dc << "MM_NONE";
  1063.         break;
  1064.     case MM_SCALETOFIT:
  1065.         dc << "MM_SCALETOFIT";
  1066.         break;
  1067.     case MM_TEXT:
  1068.         dc << "MM_TEXT";
  1069.         break;
  1070. #if !defined(_WIN32_WCE_NO_GDITRANSFORM)
  1071.     case MM_LOMETRIC:
  1072.         dc << "MM_LOMETRIC";
  1073.         break;
  1074.     case MM_HIMETRIC:
  1075.         dc << "MM_HIMETRIC";
  1076.         break;
  1077.     case MM_LOENGLISH:
  1078.         dc << "MM_LOENGLISH";
  1079.         break;
  1080.     case MM_HIENGLISH:
  1081.         dc << "MM_HIENGLISH";
  1082.         break;
  1083.     case MM_TWIPS:
  1084.         dc << "MM_TWIPS";
  1085.         break;
  1086. #endif // _WIN32_WCE_NO_GDITRANSFORM
  1087.     default:
  1088.         dc << "*unknown*";
  1089.         break;
  1090.     }
  1091.  
  1092.     dc << "\n";
  1093. }
  1094.  
  1095. void CScrollView::AssertValid() const
  1096. {
  1097.     CView::AssertValid();
  1098.  
  1099.     switch (m_nMapMode)
  1100.     {
  1101.     case MM_NONE:
  1102.     case MM_SCALETOFIT:
  1103.     case MM_TEXT:
  1104. #if !defined(_WIN32_WCE_NO_GDITRANSFORM)
  1105.     case MM_LOMETRIC:
  1106.     case MM_HIMETRIC:
  1107.     case MM_LOENGLISH:
  1108.     case MM_HIENGLISH:
  1109.     case MM_TWIPS:
  1110. #endif // _WIN32_WCE_NO_GDITRANSFORM
  1111.         break;
  1112. #if !defined(_WIN32_WCE_NO_GDITRANSFORM)
  1113.     case MM_ISOTROPIC:
  1114.     case MM_ANISOTROPIC:
  1115.         ASSERT(FALSE); // illegal mapping mode
  1116. #endif // _WIN32_WCE_NO_GDITRANSFORM
  1117.     default:
  1118.         ASSERT(FALSE); // unknown mapping mode
  1119.     }
  1120. }
  1121. #endif //_DEBUG
  1122.  
  1123. #ifdef AFX_INIT_SEG
  1124. #pragma code_seg(AFX_INIT_SEG)
  1125. #endif
  1126.  
  1127. IMPLEMENT_DYNAMIC(CScrollView, CView)
  1128.  
  1129. /////////////////////////////////////////////////////////////////////////////
  1130.